import UIKit
import LXExtensions
protocol XTableManagerDelegate: NSObjectProtocol {
    func managerDidScroll(manager:XTableManager, scrollView:UIScrollView)
    func managerDidEndScroll(manager:XTableManager, scrollView:UIScrollView)
    func managerDidLoadCell(manager:XTableManager,
                            rowModel:XTableRow,
                            cell:UITableViewCell,
                            at indexPath:IndexPath)
    func managerDidLoadHeader(manager:XTableManager,
                              tableSection:XTableSection,
                                    headerFooter:UITableViewHeaderFooterView,
                                    at section:Int)
    func managerDidLoadFooter(manager:XTableManager,
                                    tableSection:XTableSection,
                                    headerFooter:UITableViewHeaderFooterView,
                                    at section:Int)
    func managerDidClickedCell(tableManager:XTableManager,
                            rowModel:XTableRow,
                            at indexPath:IndexPath)
    func managerDidReloadData(manager:XTableManager)
}
extension XTableManagerDelegate {
    func managerDidScroll(manager:XTableManager, scrollView:UIScrollView){
    }
    func managerDidEndScroll(manager:XTableManager, scrollView:UIScrollView){
    }
    func managerDidLoadCell(manager:XTableManager,
                            rowModel:XTableRow,
                            cell:UITableViewCell,
                            at indexPath:IndexPath){
    }
    func managerDidClickedCell(tableManager:XTableManager,
                            rowModel:XTableRow,
                            at indexPath:IndexPath){
    }
    func managerDidLoadHeader(manager:XTableManager,
                              tableSection:XTableSection,
                                    headerFooter:UITableViewHeaderFooterView,
                                    at section:Int) {
    }
    func managerDidLoadFooter(manager:XTableManager,
                              tableSection:XTableSection,
                                    headerFooter:UITableViewHeaderFooterView,
                                    at section:Int) {
    }
    func managerDidReloadData(manager:XTableManager){
    }
}
class XTableManager: NSObject {
    var sections:[XTableSection] = []{
        didSet {
        }
    }
    override init() {
        super.init()
        defaultView()
    }
    init(style:UITableView.Style) {
        super.init()
        tableView = UITableView.init(frame: .zero, style: style)
        if #available(iOS 15.0, *) {
            tableView.sectionHeaderTopPadding = 0
        }
        defaultView()
    }
    weak var delegate :XTableManagerDelegate?
    var tableView: UITableView = UITableView.init(frame: .zero, style: .grouped) {
        didSet {
            defaultView()
        }
    }
    func defaultView() {
        tableView.lx.registerCellClass(UITableViewCell.self)
        tableView.lx.registerHeaderFooterClass(UITableViewHeaderFooterView.self)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.contentInsetAdjustmentBehavior = .never
    }
    func animate(updates:(() -> Void)?, completion: ((Bool) -> Void)? = nil) {
        tableView.performBatchUpdates(updates, completion: completion)
    }
    func reloadData() {
        tableView.reloadData()
    }
    func appendSections(newSections:[XTableSection]) {
        let firstIndex = sections.count
        sections.append(contentsOf: newSections)
        tableView.insertSections(IndexSet(firstIndex..<newSections.count + firstIndex), with: .automatic)
    }
    func appendRows(newRows:[XTableRow]) {
        let section: XTableSection
        let sectionIndex: Int
        if let sec = sections.last {
            section = sec
            sectionIndex = sections.count - 1
        }else{
            section = XTableSection()
            sectionIndex = 0
        }
        let rowFirstIndex = section.rows.count
        let indexPaths: [IndexPath] = stride(from: rowFirstIndex, to: rowFirstIndex + newRows.count, by: 1).map { value in
            return IndexPath(row: value, section: sectionIndex)
        }
        section.rows.append(contentsOf: newRows)
        tableView.insertRows(at: indexPaths, with: .automatic)
    }
}
extension XTableManager: UITableViewDelegate, UITableViewDataSource {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        delegate?.managerDidScroll(manager: self, scrollView: scrollView)
    }
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        DispatchQueue.main.async {
            self.delegate?.managerDidEndScroll(manager: self, scrollView: scrollView)
        }
    }
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            DispatchQueue.main.async {
                self.delegate?.managerDidEndScroll(manager: self, scrollView: scrollView)
            }
        }
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].rows.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let xrow = sections[indexPath.section].rows[indexPath.row]
        let cell = tableView.lx.dequeueReusableCell(xrow.clsName, indexPath: indexPath)!
        cell.accessoryType = xrow.accessoryType
        cell.selectionStyle = xrow.selectionStyle
        cell.accessoryView = xrow.accessoryView
        cell.contentView.isUserInteractionEnabled = xrow.isUserInteractionEnabled
        if let prot = cell as? XTableRowProtocol {
            prot.x_dataSourceDidSet(xrow)
        }else if cell.responds(to: NSSelectorFromString("x_dataSourceDidSet:")) {
            cell.perform(NSSelectorFromString("x_dataSourceDidSet:"), with: xrow)
        }
        delegate?.managerDidLoadCell(manager: self, rowModel: xrow, cell: cell, at: indexPath)
        return cell
    }
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let xrow = sections[indexPath.section].rows[indexPath.row]
        if let prot = cell as? XTableRowProtocol {
            prot.x_dataSourceWillDisplay(xrow)
        }else if cell.responds(to: NSSelectorFromString("x_dataSourceWillDisplay:")) {
            cell.perform(NSSelectorFromString("x_dataSourceWillDisplay:"), with: xrow)
        }
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let xrow = sections[indexPath.section].rows[indexPath.row]
        delegate?.managerDidClickedCell(tableManager: self, rowModel: xrow, at: indexPath)
        xrow.delegate?.rowDidSelect(row: xrow, at: indexPath)
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        let xrow = sections[indexPath.section].rows[indexPath.row]
        return xrow.height
    }
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return sections[section].header.height
    }
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return sections[section].footer.height
    }
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = sections[section].header
        let view = tableView.lx.dequeueReusableHeaderFooter(header.clsName)!
        if #available(iOS 14.0, *) {
            var config = UIBackgroundConfiguration.clear()
            config.backgroundColor = header.backgroundColor
            view.backgroundConfiguration = config
        } else {
            view.backgroundColor = header.backgroundColor
            view.contentView.backgroundColor = header.backgroundColor
        }
        delegate?.managerDidLoadHeader(manager: self, tableSection: sections[section], headerFooter: view, at: section)
        if let prot = view as? XTableHeaderFooterProtocol {
            prot.x_dataSourceDidSet(header)
        }else if view.responds(to: NSSelectorFromString("x_dataSourceDidSet:")) {
            view.perform(NSSelectorFromString("x_dataSourceDidSet:"), with: header)
        }
        return view
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let footer = sections[section].footer
        let view = tableView.lx.dequeueReusableHeaderFooter(footer.clsName)!
        if #available(iOS 14.0, *) {
            var config = UIBackgroundConfiguration.clear()
            config.backgroundColor = footer.backgroundColor
            view.backgroundConfiguration = config
        } else {
            view.backgroundColor = footer.backgroundColor
            view.contentView.backgroundColor = footer.backgroundColor
        }
        delegate?.managerDidLoadFooter(manager: self, tableSection: sections[section], headerFooter: view, at: section)
        if let prot = view as? XTableHeaderFooterProtocol {
            prot.x_dataSourceDidSet(footer)
        }else if view.responds(to: NSSelectorFromString("x_dataSourceDidSet:")) {
            view.perform(NSSelectorFromString("x_dataSourceDidSet:"), with: footer)
        }
        return view
    }
}
class XTableSection: NSObject {
    var header : XTableHeaderFooter = XTableHeaderFooter()
    var footer : XTableHeaderFooter = XTableHeaderFooter()
    var rows : [XTableRow] = []
}


protocol XTableRowDelegate: NSObjectProtocol {
    func rowDidSelect(row: XTableRow, cell: UITableViewCell, at indexPath: IndexPath)
    func rowNeedRemove(row: XTableRow, cell: UITableViewCell, at indexPath: IndexPath)
}

extension XTableRowDelegate {
    func rowDidSelect(row: XTableRow, at indexPath: IndexPath) {
        
    }
    
    func rowNeedRemove(row: XTableRow, at indexPath: IndexPath) {
        _ = row.removeFromTable()
    }
}

class XTableRow: NSObject {
    var height :CGFloat = UITableView.automaticDimension
    var selectionStyle: UITableViewCell.SelectionStyle = .none
    var accessoryType: UITableViewCell.AccessoryType = .none
    var accessoryView: UIView? = nil
    var isUserInteractionEnabled: Bool = true

    var clsName: UITableViewCell.Type = UITableViewCell.self
    var xmodel :Any?
    var extraData :Any?
    var identify :String?
    var indexPath :IndexPath?
    weak var tableManager: XTableManager?
    var customRemoveBlock: (()->())?
    weak var delegate: XTableRowDelegate?
    
    override init() {
        super.init()
        customRemoveBlock = { [weak self] in
            _ = self?.removeFromTable()
        }
    }
    func removeFromTable(animated: Bool = false) -> Bool {
        guard let manager = tableManager else { return false }
        guard let indexPath = indexPath else { return false }
        if manager.sections.count <= indexPath.section {
            return false
        }
        let section = manager.sections[indexPath.section]
        if section.rows.count <= indexPath.row {
            return false
        }
        section.rows.remove(at: indexPath.row)
        if animated {
            manager.animate {
                manager.reloadData()
            }
        }else{
            manager.reloadData()
        }
        return true
    }
}
class XTableHeaderFooter: NSObject {
    var clsName: UITableViewHeaderFooterView.Type = UITableViewHeaderFooterView.self
    var xmodel :Any?
    var height: CGFloat = 0.1
    var backgroundColor: UIColor = .clear
}
protocol XTableRowProtocol {
    func x_dataSourceDidSet(_ xRow:XTableRow)
    func x_dataSourceWillDisplay(_ xRow:XTableRow)
}
extension XTableRowProtocol {
    func x_dataSourceWillDisplay(_ xRow:XTableRow) {
    }
}
protocol XTableHeaderFooterProtocol {
    func x_dataSourceDidSet(_ xHeaderFooter:XTableHeaderFooter)
}
